package com.shy.springframework.beans.factory.support;

import com.shy.springframework.beans.BeansException;
import com.shy.springframework.beans.factory.DisposableBean;
import com.shy.springframework.beans.factory.ObjectFactory;
import com.shy.springframework.beans.factory.config.SingletonBeanRegistry;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author yzpang
 * @desc: 单例Bean注册/获取接口实现类
 * @date: 2023/2/7 14:22
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    protected static final Object NULL_OBJECT = new Object();
    // 一级缓存,存放普通成品对象
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    // 二级缓存,存放提前暴露,未实例化完成的对象
    private final Map<String, Object> earlySingletonObjects = new HashMap<>();
    // 三级缓存,存放代理对象
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

    private Map<String, DisposableBean> disposableBeans = new ConcurrentHashMap<>();

    @Override
    public Object getSingleton(String beanName) {
        Object singletonObject = singletonObjects.get(beanName);
        // 一级缓存为空
        if (null == singletonObject){
            singletonObject = earlySingletonObjects.get(beanName);
            // 二级缓存为空
            if (null == singletonObject){
                ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
                // 三级缓存不为空
                if (null != singletonFactory){
                    singletonObject = singletonFactory.getObject();
                    earlySingletonObjects.put(beanName, singletonObject);
                    singletonFactories.remove(beanName);
                }
            }
        }
        return singletonObject;
    }

    /**
     * 单例Bean注册
     * @param beanName
     * @param singletonObject
     */
    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);
    }

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory){
        if (!singletonObjects.containsKey(beanName)){
            singletonFactories.put(beanName, singletonFactory);
            earlySingletonObjects.remove(beanName);
        }
    }

    /**
     * 注册bean销毁对象
     * @param beanName
     * @param bean
     */
    public void registerDisposableBean(String beanName, DisposableBean bean){
        this.disposableBeans.put(beanName, bean);
    }

    public void destroySingletons(){
        Set<String> keySet = this.disposableBeans.keySet();
        Object[] disposableNames = keySet.toArray();
        for (int i = disposableNames.length - 1; i >= 0; i--) {
            Object beanName = disposableNames[i];
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + beanName + "', threw an exception", e);
            }
        }
    }
}
